/* 柯里化（颗粒化） */
function fn5() {
  const curry = (fn) => {
    // add进去 颗粒化了的add出来
    return function curriedFn(a) {
      // 第一次的入参2存在闭包里
      return function (b) {
        // 龙珠已凑齐 调用原始的add 二三得五 返回之
        return fn(a, b);
      };
    };
  };

  const add = (a, b) => a + b;

  // add进去 颗粒化了的add出来
  const curriedAdd = curry(add);
  console.log(curriedAdd(2)(3));
}
// fn5()

function fn51() {
  const curry = (fn) => {
    // 调用cadd即调用此函数
    return function (a) {
      // 第一个入参a已经被封锁在外层闭包中了
      return function (b) {
        // 直接调用add(a,b)
        return fn(a, b);
      };
    };
  };

  const add = (a, b) => a + b;
  const cAdd = curry(add);
  console.log(cAdd(2)(3));
}
// fn51()

/* 多参柯里化 */
function fn6() {
  const curry = (fn) => {
    return function cfn(...args) {
      // 参数长度够了的时候 直接调用fn求得结果并返回
      // 函数长度即参数列表的长度
      if (args.length === fn.length) {
        return fn(...args);
      }

      /* 喂进来的参数数量不够时 返回一个函数以便继续接收下一批次的参数 */
      // cadd(1,2)(3)
      return function (...b) {
        // 调用f(3)的时候...
        // 先将参数3拼合到闭包中的args里去 形成[1,2,3]
        args = args.concat(b); //[1,2,3]

        // 再形成cadd(1,2,3)的效果
        return cfn(...args); //管你是最终结果还是继续接收入参的新函数 还给你
      };
    };
  };

  // add函数进去 颗粒化了的cadd函数出来
  const add = (a, b, c, d) => a + b + c + d;
  const cadd = curry(add);

  // 一次性给够参数 = add(1,2,3,4)
  console.log(cadd(1, 2, 3, 4)); //10
  console.log(cadd(1)(2)(3)(4)); //10
  console.log(cadd(1, 2)(3)(4)); //10
}
// fn6()

/* 组合函数 */
function fn7() {
  function double(a) {
    return a * 2;
  }

  function triple(b) {
    return b * 3;
  }

  /* 
  组合高阶函数 
  两个函数进去：返回一个组合后的函数
  组合函数的功能：先用b处理 结果再用a处理 返回最终结果
  从右往左 流水作业
  */
  // const compose = (a, b) => function(c){
  //   return a( b(c) )
  // }
  const compose = (a, b) => (value) => a(b(value));

  // 将两个函数做组合
  let cfn = compose(double, triple);
  console.log(cfn(2)); //先对2城三 再将结果成二 12
}
// fn7()

/* 管道函数 */
function fn8() {
  /* 
  管道函数：a,b函数进去 组合函数出来 
  组合函数功能：value进去 先用a处理 结果再用b处理 结果再用c处理 返回最终结果
  */
  const pipe = (a, b, c) => (val) => c(b(a(val)));

  /* 求n的长度 */
  const len = (n) => (n + "").length; //求数值的长度
  const pow = (n) => n * n; //求n的平方
  const log = (n) => console.log(n); //打印n

  /* 生成流水线函数：先长度=>对长度做平方=>打印平方值 */
  const streamline = pipe(len, pow, log);

  streamline(10); //4
}
// fn8()

/* 任意多个函数串联成【管道/组合】 */
function fn9() {
  /* 管道 */
  // const pipe = (a,b,c)=>v=>c(b(a(v)))
  const pipe =
    (...fns) =>
    (v) =>
      fns.reduce((pv, fn) => fn(pv), v);
  const compose =
    (...fns) =>
    (v) =>
      fns.reverse().reduce((pv, fn) => fn(pv), v);

  //求数值的长度
  const len = (n) => {
    console.log("len", n);
    return (n + "").length;
  };

  //求n的平方
  const pow = (n) => {
    console.log("pow", n);
    return n * n;
  };

  // 求立方根
  const cubicRoot = (n) => {
    console.log("cubicRoot", n);
    return Math.cbrt(n)
  };

  // 从左往右处理
  // console.log(pipe(len, pow, cubicRoot)(10));

  // 从右往左处理
  console.log(compose(len, pow, cubicRoot)(1000));
}
fn9();
